/*
	 
iTransmogrify!

by: Joe Maller 
	joe@joemaller.com
	
Project: http://itransmogrify.googlecode.com/


The following code will be injected into whatever page you're viewing,
automatically detecting and converting many embedded Flash links into 
clickable image links which open in the Safari or the iPhone YouTube player.

Please don't paste this code directly into a page or bookmark. Using the
bookmarklet will automatically pull the most recent stable version of
the code from the Google Code repository.


// javascript:if%28typeof%28iTransmogrify%29%3D%3D%27undefined%27%29%7Bvar%20s%3Ddocument.createElement%28%27script%27%29%3Bs.src%3D%27http%3A%2F%2Fitransmogrify.googlecode.com%2Ffiles%2FiTransmogrify.js%3Fq%3D%27%2B%28new%20Date%29.getTime%28%29%3Bdocument.getElementsByTagName%28%27head%27%29%5B0%5D.appendChild%28s%29%7Dvoid%280%29
if(typeof(iTransmogrify)=='undefined'){
var s=document.createElement('script');
s.src='http://itransmogrify.googlecode.com/files/iTransmogrify.js?q='+(new Date).getTime();
document.getElementsByTagName('head')[0].appendChild(s)
}void(0)

*/



iTransmogrify = {
	jQueryURL: 'http://jqueryjs.googlecode.com/files/jquery-1.2.3.min.js',	// grab JQuery from Google Code
	appleQuickTimeLib: 'http://wdirect.apple.com/main/js/ac_quicktime.js',
	joesInfoURL: 'http://itransmogrify.googlecode.com/',
	imageBaseURL: 'http://itransmogrify.googlecode.com/svn/trunk/images/',	// grab interface images from Google Code SVN

	YTregex: /(?:youtube.com\/v\/|youtube.com\/watch\?v=)([^ .?=&]{11})/, // returns YTids from http://www.youtube.com/v/TOpn32Gg88A and http://www.youtube.com/watch?v=TOpn32Gg88A urls
	YTinternalRegex: /(?:video_id=|watch\?v=)([^ .?=&]{11})/, // regex for extracting YTid from YouTube internal pages like bios, channels, etc
	mp3regex: /=((?:http|\/)[^&]*\.mp3)/,	// extracts full-path URLs ending in .mp3 from query strings used frequently in param flashvars
    DMregex: /http:\/\/www.dailymotion.com\/swf\/([\S]+)/, // grab DailyMotion url IDs from swf sources

    // imageBaseURL: 'http://joes-mbp.local:9009/images/',  // use local images
                
	init: function() {
	    parentObject = this; // defined globally for convenience, probably sloppy 
	    if ( this.jQueryVersion = /-([0-9.]+)\.min.js/.exec(this.jQueryURL) )
            this.jQueryVersion = this.jQueryVersion[1];
		if ( typeof jQuery == "undefined" || jQuery.prototype.jquery < this.jQueryVersion ){	// jQuery is not loaded on the page yet or is an older version
			var s = document.createElement('script'),
			    loaded = function() {
			        jQuery.noConflict();
			        parentObject.getObjectAndEmbeds();
		        };
			s.src = this.jQueryURL;
			s.onload = loaded;  // onload handler supported by Safari and Firefox
			s.onreadystatechange = function() { if (this.readyState == 'complete') { loaded() } }; // 'onload' handler for IE
			document.getElementsByTagName('head')[0].appendChild(s);
		} else {
			this.getObjectAndEmbeds()
		}

	},
	
	getObjectAndEmbeds: function(iframe) {
		// function returns an array of objects like {type:'type', jquery object, YTid/url}
		// supported types: youtube, mp3
		var YouTubeItems, mp3Tags, foundObjects = [];

        if (iframe) var context = iframe.contents();

		// Standard YouTube items:
        YouTubeItems = jQuery("embed[src*='youtube.com']", context); // get standard YouTube embeds and UFO inserted Webkit bare-embeds
        YouTubeItems = YouTubeItems.add( jQuery("object[src*=youtube.com], object[data*=youtube.com]", context) ); // get Mozilla UFO bare objects
		
        // YouTube originated pages:
		if ( window.location.host.match( /youtube.com$/ ) ) {
            // Grab embeds from YouTube bio pages
            YouTubeItems = YouTubeItems.add(jQuery('.profileEmbedVideo object param[value*="video_id"]', context)); 

            // if playerDiv exists, we're on a functioning page so go replace playerDiv's contents
            jQuery('#playerDiv, #watch-player-div', context).each( function() {    
                
                var temp = jQuery( document.createElement('div') ).css( { width: jQuery(this).width(), height: jQuery(this).height() } )
                jQuery(this).empty().append( temp );
                
                foundObjects.push( {
                    _type: 'youtube',
                    _obj: jQuery(this).children('div'),
                    _id: parentObject.YTinternalRegex.exec( window.location.toString() )[1]
                })
            })
        }


 		YouTubeItems.each(function() {
 		    jQuery(this).children()
            foundObjects.push( {
                _type: 'youtube',
                _obj: function(item) {
                    if ( !context )
                        return ( jQuery(item).parent().is('object') ) ? jQuery(item).parent() : jQuery(item);
                    }(this),
                _id: parentObject.getYTid(this)
            });
        });	
          
           
    	// collect mp3 items:
		mp3Tags = jQuery("param[value*='.mp3']", context).filter( function() { return this.name.toLowerCase() == "flashvars"; });    // players using FlashVars
        mp3Tags = mp3Tags.add(jQuery("embed[flashvars*='.mp3']", context));
        mp3Tags = mp3Tags.add(jQuery("param[value*='.mp3']", context).filter( function() { return this.value.indexOf('mp3_file') > -1; }));  // for kink.fm
        
		mp3Tags.each(function() {
    		var mp3url;
		    if (mp3url = parentObject.getMP3url(this)) {
			    foundObjects.push( {
								_type: 'mp3', 
                                _obj: function(item) { 
                                        // figure out which DOM object to replace
                                        if (iframe && iframe.attr('id').indexOf('iTransmogrify_') == 0)   // this is a created iFrame
                                            return iframe;
                                            
                                        if( jQuery(item).parent().is('object') ) 
                                            return jQuery(item).parent();
                                            
                                        return jQuery(item);
                                    }(this),
								_mp3: mp3url
								});
	        }
		});

// working on these:
        this.getVodPodEmbeds(context);
        this.sevenload.get(context);
        this.flickr.get(context);
        
// end

        this.blipTv.get(context);
        this.getCrunchyRollLinks(context);
        this.getViperVideoQuicktags(context);
        this.getRevverLinks(context);
        this.getFlickrBadge(context);
        this.getTedLinks(context);           // convert TED embedded and detail page videos to MP4 alternates
        this.getSideLoadLinks(context);      // convert SideLoad playback links
        this.getDailyMotionLinks(context);      // convert DailyMotion links          
        this.getKinkFmLinks(context);      // convert kink.fm links in place
        this.breakdotcom.get(context);
        
        jQuery(foundObjects).each( function() { parentObject.replaceLinks(this); } );   // do YouTube and MP3 foundObjects

        this.doStats()
        
        // grab any remaining object/embed tags and convert them
        jQuery('object').each(function(){ parentObject.replaceUnsupported( jQuery(this) ) })
        jQuery('embed').each(function(){ parentObject.replaceUnsupported( jQuery(this) ) })
        
        // load the bookmarklet for every frame on the page:
        if(!iframe)
            this.loadInFrames();
	},
	
	
	loadInFrames: function() {
        if ( iframes = jQuery('iframe') ) {
            for ( x = 0; x < iframes.length; x++ ) {
               try { this.getObjectAndEmbeds( iframes.eq(x) ) }   // try prevents errors trying to read contents of frames pointing to different domains
               catch (err) {}
            }
        }
	},


	getTedLinks: function(context) {
        var TEDitems,
            TedLookupUrl = 'http://joemaller.com/services/ted_lookup.php?ted=',
            TEDregex = /file=(http:\/\/static.videoegg.com\/ted\/movies\/[^.]+\.flv)&/;

    	if ( window.location.host.match( /ted.com$/ ) )  {    	    
            TEDitems = jQuery('#videoPlayerSwf')
        } else {
            TEDitems = jQuery('param[value*=static.videoegg.com/ted/movies]');
        }

        TEDitems.each( function() {
            var flv, obj;
           
            if ( flv = TEDregex.exec(this.value) ) {
                 flv = flv[1].split('/').pop();
                 obj = jQuery(this).parent();
            } else if ( flv = /http:\/\/(?:\w*\.)?ted.com\/.*\/([0-9]+)$/.exec(window.location.toString()) ) {
                 flv = flv[1];
                 obj = jQuery(this);
            }

            // Note we're using the newer notation here, everything will transition to match this
            jQuery.getJSON( TedLookupUrl + flv + '&callback=?', function(json){
               json._obj = obj;
               json._type = "ted";
               json._bg = "#000";
               json._w = obj.attr('width');
               json._h = obj.attr('height');
               json._duration =  json._duration.substring(3);
               
               if (json._title == '')
                    json._title = "Compatible alternate content not found."
               
               parentObject.replaceLinks( json );
               
            });
        })
	},
	
	//TODO: redo DailyMotion as an object. It's already half-broken, just start over.
	getDailyMotionLinks: function(context) {
        var interFrame,
            dailyMotionItems = jQuery("embed[src*='dailymotion.com/swf']", context); // get standard YouTube embeds and UFO inserted Webkit bare-embeds
        // dailyMotionItems = dailyMotionItems.add(jQuery("object[data*='dailymotion.com']", context)); // get Mozilla UFO bare objects
       // console.log("dailymotion items")
       // console.log(dailyMotionItems)
        dailyMotionItems.each(function() {
                      parentObject.replaceLinks( {
                          type: "dailymotion",
                          jq: jQuery(this).parent(),
                          DMid: parentObject.getDMid(this)
                      });
//         parentObject.getDMtitles(parentObject.getDMid(this));
        });
	},
	
	getViperVideoQuicktags: function(context) {
	   	// Viper Video Quicktags:  
        //     http://www.viper007bond.com/wordpress-plugins/vipers-video-quicktags/
        //     http://wordpress.org/extend/plugins/vipers-video-quicktags/
        var YTid, 
            items = jQuery('.vvqyoutube', context);

        items.each( function() {
            if(!jQuery(this).children().eq(0).is('object')) {
                if ( YTid = parentObject.YTregex.exec( jQuery(this).html() ) ) {
                          parentObject.replaceLinks( {
                              type: "youtube",
                              jq: jQuery(this),
                              YTid: YTid[1],
                              _type: 'youtube',
                              _obj: jQuery(this),
                              _id: YTid[1],
                              _img: 'http://img.youtube.com/vi/' + YTid[1] + '/0.jpg',
                              _page: 'http://www.youtube.com/watch?v=' + YTid[1],
                              _w: jQuery(this).width(),
                              _h: jQuery(this).height()
                          } );
                      
                          // parentObject.getYTTitles(YTid[1]);
                    }
                }
            }
        )
    },
	
	
	getVodPodEmbeds: function(context) {
       jQuery('embed[src^="http://widgets.vodpod.com"]', context).each( function(){
           var thisItem = this
           if ( vodPodId = /vodpod.com\/.*ExternalVideo\.([0-9]+)/.exec( jQuery(this).attr('src') ) ) {
               jQuery.getJSON( 'http://joemaller.com/services/vodpod_id_extractor.php?vodpod=' + vodPodId[1] +'&callback=?', function(json) {
                    json._obj = thisItem;
                    json._w = jQuery(thisItem).width(); 
                   // console.log(json)
                }
            )}
        })
	},
	
	flickr : {
	    get: function(context) {
            var thisParent = this, 
                flickrAPIurl = ['http://api.flickr.com/services/rest/?method=flickr.photos.getInfo&format=json&api_key=5479719afe2139329effb862462a0030&photo_id=', '&jsoncallback=?'],
                selectors = ['embed[src*=flickr.com/apps/video]'];
    
// Why is Flickr inserting a bunch of crap in the div?
// because Flickr's global.js file redefines the prototype definition of string.replace, which is then used by 
// jQuery clean() method to separate strings into tags. If a string of tags is sent, the revised string.replace is called
// and jQuery's second argument, which is a function, is dumped as text. Blah.

            if ( window.location.host.match( /flickr.com$/ ) && typeof(page_p.video_thumb_src) != 'undefined' )
                this.flickrReplace(context); // this is a flickr page


                
                jQuery(selectors.join(',')).each( function() {
                    var obj = jQuery(this);
                        photoID = /photo_id=([0-9]+)/.exec(jQuery(this).attr('flashvars'))

                    if ( photoID[1] ){
                        jQuery.getJSON( flickrAPIurl.join(photoID[1]), function(json) {

                            if ( json.stat = 'ok' )
                                json = json.photo;      // save keystrokes by jumping down a level
                                
                            json._type = 'flickrvideo';
                            json._typeLabel = 'Flickr';
                            json._page = json.urls.url[0]._content;
                            json._title = json.title._content;
                            json._img = 'http://farm' + json.farm + '.static.flickr.com/'+ json.server + '/' + json.id + '_' + json.secret + '.jpg';
                            json._obj = obj;
                            
                            parentObject.replaceUnsupported( json )
                        })
                    }
                })
            },
	    
	        flickrReplace: function(context) {
                parentObject.replaceUnsupported( { _type : 'flickrvideo',
                                                   _typeLabel : 'Flickr',
                                                   _obj : jQuery('#photoswftd .photo_gne_video_wrapper_div', context).parent(),
                                                   _page : '',
                                                   _img : page_p.video_thumb_src,
                                                   _title : page_p.title + ''
                                             } );
	        },
	},
	
	// TODO: move flickr badges into main Flickr object
	getFlickrBadge: function(context) {
        var flickrID,
            items = jQuery('.zg_div_inner iframe', context);
            
        items.each(function(){
            var item, 
                flickrID = jQuery(this).parent().find('a[href^="http://www.flickr.com/photos"]').attr('href').split('/').pop()
            
            item = jQuery('<div/>').attr('id', parentObject.nameCleaner(flickrID)).css({paddingLeft: '1px'}).replaceAll(jQuery(this));
            item.parent().after(jQuery('<div>MobileSafari enabled by <a href="http://iTransmogrify.googlecode.com" target="_new">iTransmogrify!</a></div>').css({textAlign: 'center', fontSize: '10px', lineHeight: '14px'}))

            jQuery.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?id=" + flickrID + "&format=json&jsoncallback=?", function(data){
                jQuery.each( data.items, function(i, item) {
                    jQuery('<a/>').attr( { href: item.link, title: item.title, target: '_new' } )
                            .append( jQuery("<img/>").attr( { src: item.media.m.replace('_m.jpg', '_s.jpg'), alt: item.title } )
                            .css( { width: "37px", height: "37px", margin: '0 1px 1px 0' } ) )
                            .appendTo('#' + parentObject.nameCleaner(flickrID));
                    if ( i == 11 ) return false; // mimic badge and insert 12 most recent images
                });
            });

        })
	},
	
	
	
	getRevverLinks: function(context) {
	    var revverAffiliate = '', 
    	    //  revverAffiliate = ', {"affiliate": 169801}',  // Add affiliate links pending response from Revver
	        revverAPI = ['https://api.revver.com/json/1.0?method=open.video.find&params=[{"ids":[',']},["id","title","duration", "quicktimeMediaUrl", ["thumbnailUrl",{}], "status"]' + revverAffiliate + ']&callback=?'],
            revverItems = jQuery( 'script[src*=flash.revver.com], embed[src*=flash.revver.com/player]', context)

        revverItems.each( function() {
            var mediaId, affiliateId, w, h, obj;                
            if ( jQuery(this).is('script') ) {
                if ( mediaId = /mediaId:([0-9]+)/.exec( jQuery(this).attr('src') ) ) mediaId = mediaId[1];
                if ( affiliateId = /affiliateId:([0-9]+)/.exec( jQuery(this).attr('src') ) ) affiliateId = affiliateId[1];
                if ( w = /width:([0-9]+)/.exec(jQuery(this).attr('src')) ) w = w[1];
                if ( h = /height:([0-9]+)/.exec(jQuery(this).attr('src')) ) h = h[1];

                obj = jQuery(this);
                if ( obj = jQuery('div[id^=revver' + mediaId + ']') )
                    jQuery(this).remove(); // remove the scripts and use the div instead
            }
                            
            if ( jQuery(this).is('embed') ) {
                if ( mediaId = /mediaId=([0-9]+)/.exec( jQuery(this).attr('src') ) ) mediaId = mediaId[1];
                if ( affiliateId = /affiliateId=([0-9]+)/.exec( jQuery(this).attr('src') ) ) affiliateId = affiliateId[1];
                if ( w = jQuery(this).attr('width') ) {};
                if ( h = jQuery(this).attr('height') ) {};

                obj = jQuery(this);
                if ( jQuery(this).parent().is('object') ) 
                    obj = jQuery(this).parent()
            }
                    
            if ( mediaId ) { 
                jQuery.getJSON( revverAPI.join(mediaId), function(json){

                    // revver returns a single item array, so cast that right away to save keystrokes
                    json = json[0];
                    if ( json.status == 'online' ) {
                        json._img = json.thumbnailUrl;
                        json._obj = obj;
                        json._id = mediaId;
                        json._page = 'http://www.revver.com/video/' + json._id;
                        json._type = 'revver';
                        json._mp4 = json.quicktimeMediaUrl;
                        json._title = json.title;
                        json._bg = "#000";
                        json._duration = parentObject.formatSeconds(json.duration)
                    } 
                    json._w = w;
                    json._h = h;
                    if ( json.status != 'online' ) json._title = "Revver Video status: " + json.status;

                    parentObject.replaceLinks( json );
                });
            }           
        })
	},
	
	
	getDMtitles: function(DMid) {
	   var DMTitleURL = 'http://pipes.yahoo.com/joemaller/dmtitles?_render=json&DMid=' + DMid + '&_callback=?';
	   
	    jQuery.getJSON( DMTitleURL + '', function(json){
            var title = [];
            jQuery.each( json.value.items, function(item, i){ title.push (i.content) })
            parentObject.swapTitle(jQuery('#' + parentObject.nameCleaner(DMid) + ' .YTtitle'), title.join(' - '));
            // console.log(json)
            // console.log(title)
            
            // TODO: Is this even working?
        });
	},	
	

    blipTv: {
        'get': function(context) {
            var thisParent = this, 
                selectors = [ 'param[value*=blip.tv]',              // legacy player embed code
                              'embed[src*=blip.tv/play]',           // new-style player embed
                              'embed[src*=blip.tv/scripts/flash]',  // new-style player embed
                              'div[id^=blip_movie_content_]'        // legacy player
                            ];
                            //TODO: not replacing embeds on Mahalo Daily, no ID?:   http://daily.mahalo.com/2007/12/06/md019-the-room-interview-with-tommy-wiseau/

            jQuery(selectors.join(',')).each( function() {
                JSONurl = thisParent.getId(this);
                var obj = ( jQuery(this).parent().is('object') ) ? jQuery(this).parent() : jQuery(this);
                if (JSONurl) {
                    thisParent.JSONreplace(obj, JSONurl);
                }
            })
        },
        
        getId: function(item) {
            var id,
                blip_jsonUrl = ['http://blip.tv/', '?skin=json&file_type=m4v&callback=?'],
                blip_id_translator = "http://joemaller.com/services/blip_id_extractor.php?blip=";
                
            if ( id = /_([0-9]+)$/.exec(item.id) ){
                return blip_jsonUrl.join( 'posts/' + id[1]);}

            if ( id = /blip.tv\/rss\/flash\/([0-9]+)&/.exec( item.value ) )
                return blip_jsonUrl.join( 'posts/' + id[1] );

            if ( id = /blip.tv\/rss\/flash\/([0-9]+)&/.exec( unescape(item.src)  ) )
                return blip_jsonUrl.join( 'posts/' + id[1] );

            if ( id = /blip.tv\/(file|posts)\/([0-9]+)/.exec( (item.value) ) )
                return blip_jsonUrl.join( id[1] + '/' + id[2] );

            if ( id = /blip.tv\/play\/(.*)/.exec( (item.src) ) )    // new style IDs
                return blip_id_translator + id[1]+ '&callback=?';
        },
        
        JSONreplace: function(obj, JSONurl) {
            jQuery.getJSON( JSONurl, function(json){
               
                if (json.value){
                    // Yahoo! pipes bookmark handler, recast the variable with a subelement to save keystrokes
                    json = json.value.items[0];
                } else {
                    // standard Blip json response, result is a single array, cast that right away to save keystrokes
                    json = json[0].Post;
                }

                // remap some of the renamed items from Yahoo Pipes
                // also check media:group for .m4v and .mp4 media files.
                if ( json['media:group']){
                    var i;
                    for (i in json['media:group']['media:content']) {
                        if ( json['media:group']['media:content'][i].url.match(/\.m4v|mp4/) ){
                            json.media = json['media:group']['media:content'][i]
                            json.media.duration = json['blip:runtime']
                            break;
                        }
                    }
                    json.thumbnailUrl = json['media:thumbnail'].url;
                };

                json._type = 'blip.tv';
                json._typeLabel = 'blip.tv';
                json._obj = obj;
                json._img = json.thumbnailUrl;
                json._id = json.itemId;
                json._page = json.url;
                json._title = json.title;
                json._w = (json._obj.attr('width')) ? json._obj.attr('width') : json._obj.width();
                json._h = (json._obj.attr('height')) ? json._obj.attr('height') : json._obj.height();
                json._bg = "#000";

                if ( json.media.url.match(/\.m4v|mp4/) ){                    
                    // console.log('in match: '+ json._title)
                    json._mp4 = json.media.url;
                    json._duration = parentObject.formatSeconds(json.media.duration);

                    parentObject.replaceLinks( json );
                } else {
                    // console.log('in match: '+ json._title)
                    parentObject.replaceUnsupported( json );
                }
            });
        }
    },
    
    
    breakdotcom: {
        'get': function(context) {
            var thisParent = this, 
                selectors = [ 'param[value*=embed.break.com]',            
                              'embed[src*=embed.break.com]',
                              '#playerwrap #defaultDiv object',
                              '#playerwrap #defaultDiv embed'          
                            ];

            jQuery(selectors.join(',')).each( function() {

                var obj = ( jQuery(this).parent().is('object') ) ? jQuery(this).parent() : jQuery(this);
                if ( JSONurl = thisParent.getId(this) )
                    thisParent.JSONreplace(obj, JSONurl);
            })
        },
        
        getId: function(item) {
            var id,
                breakRegex = /embed.break.com\/([^&"]*)/,
                jsonUrl = ['http://joemaller.com/services/break_extractor.php?break=', '&callback=?'];
                
            if ( (id = breakRegex.exec(item.value)) || (id = breakRegex.exec(item.src)))
                return jsonUrl.join( id[1] )

            if( id = breakRegex.exec(jQuery('textarea').text()) )
                return jsonUrl.join( id[1] )
        },
        
        JSONreplace: function(obj, JSONurl) {
            jQuery.getJSON( JSONurl, function(json){
                json._obj = obj;
                if ( window.location.host.match( /break.com$/ ) ) {
                    json._title = document.title.substring( 0, document.title.length - 6 );
                    json._page = '';    // link would be circular, but not excepted because of the redirect, remove the link.
                }
                parentObject.replaceUnsupported( json );
            })
        }
    },
    
    
    sevenload: {
        'get': function(context) {
            var thisParent = this, 
                selectors = [ 'script[src*=sevenload.com]',            
                              'object[id^=sevenloadPlayer_]'          
                            ];

            jQuery(selectors.join(','), context).each( function() {
                if ( jQuery(this).is('script') ){
                    var parts = /\/\/([^.]*\.)sevenload.com\/pl\/([^\/]+)\/([0-9]+)x([0-9]+)/.exec(this.src)
                    
                    obj = jQuery(this);
                    if ( obj = jQuery('object[id^=sevenloadPlayer_' + parts[2] + ']') )
                        jQuery(this).remove(); // remove the scripts and use the div instead
                        
                    parentObject.replaceUnsupported( { _type : 'sevenload',
                                                       _typeLabel : 'sevenload',
                                                       _obj : obj,
                                                       _w : Number( parts[3] ),
                                                       _h : Number( parts[4] ),
                                                       _page : 'http://' + parts[1] + 'sevenload.com/videos/' + parts[2],
                                                       _title : 'Video Page'
                                                      } );
                }
            })
        },
        
        getId: function(item) {
            var id,
                breakRegex = /embed.break.com\/([^&"]*)/,
                jsonUrl = ['http://joemaller.com/services/break_extractor.php?break=', '&callback=?'];
                
            if ( (id = breakRegex.exec(item.value)) || (id = breakRegex.exec(item.src)))
                return jsonUrl.join( id[1] )

            if( id = breakRegex.exec(jQuery('textarea').text()) )
                return jsonUrl.join( id[1] )
        },
        
        JSONreplace: function(obj, JSONurl) {
            jQuery.getJSON( JSONurl, function(json){
                json._obj = obj;
                if ( window.location.host.match( /break.com$/ ) ) {
                    json._title = document.title.substring( 0, document.title.length - 6 );
                    json._page = '';    // link would be circular, but not excepted because of the redirect, remove the link.
                }
                parentObject.replaceUnsupported( json );
            })
        }
    },
    
    getCrunchyRollLinks: function(context) {
        // this all works, the problem is with the h.264 encodes on crunchyroll.com, they're not iPhone compatible
        // leaving it in, just in case they fix stuff
    	if ( window.location.host.match( /crunchyroll.com$/ ) ) {
            var crunchyMp4 = /file=((?:[^&]+video.mp4)|(?:.*format=h264))/.exec(unescape(window.FO.flashvars));
            if ( crunchyMp4[1] ) {
               this.replaceLinks( {
                    _type: 'mp4',
                    _obj: jQuery('#embed_vid').empty(),
                    _img: crunchyMp4[1],
                    _page: document.location.href,
                    _title: document.title.substring(14),
                    _mp4: crunchyMp4[1],
                    _duration: '--:--',
                	_w: jQuery('#embed_vid').width(),
                	_h: jQuery('#embed_vid').height(),
                	_bg: '#000'
                } )
            }
        }
    },
    

    getSideLoadLinks: function(context) {
        // rather than doing all sorts of ninja sleector hackery, we're just going to replace their function. Hizzah!
        if (typeof(flashProxy) == 'undefined')  return false    // bail out if there are no sideload links
        flashProxy.call = function(blah, mp3url, mp3Title) {return false;}
        
        // the stack idea is from http://fmarcia.info/jquery/stack/
        // referenced here: http://groups.google.com/group/jquery-en/browse_thread/thread/456709277ec26679/68dcabe65083212c?lnk=gst&q=each+delay#68dcabe65083212c
        
        var stack = {
			'delay': 50,
			'actions': [],
			'run': function() {
				if ( stack.actions.length ) {
				     stack.actions.shift()();
				     setTimeout(stack.run, stack.delay);
				}
			}
		};
		
        
        jQuery('a[href*=flashProxy]').each(function(){
            
            var mp3Parts = (/'\s*,\s*'(.*)'\s*,\s*'(.*)'\)/).exec(this.href),
                newRow = jQuery(this).parent().parent().after('<tr height="36"><td colspan="99" ><p/></td></tr>').next().find('p'),
                button = {
                    type: "mp3",
                    jq: newRow,
                    url: mp3Parts[1],
                    title: unescape(mp3Parts[2])
                };
            
            stack.actions.push(function(){
                parentObject.replaceLinks( button );
            })
        })
        stack.run();
    },
    
	
	getKinkFmLinks: function(context) {
   		var buttons = jQuery('a img[src*="play_button.gif"]', context).parent(),
   		    kinkRegex = /, ?(\d+)\)/;   // extract kink id from javascript links

        buttons.each( function() {

            if ( kinkPageID = kinkRegex.exec( jQuery(this).attr('href') ) )
                 kinkPageID = kinkPageID[1];

            parentObject.replaceLinks( {
                type: "mp3",
                jq: jQuery(this),
                url:kinkPageID
            } );

            jQuery( '#' + parentObject.nameCleaner(kinkPageID) ).find('.YTtitle').html('Click to fetch mp3 address');
            jQuery( '#' + parentObject.nameCleaner(kinkPageID) ).click( function() {
    
                var kinkSource, kinkTitle;
                currentItem = this.id;

                parentObject.swapTitle(jQuery('#' + currentItem).find('.YTtitle'), 'fetching address...');   // Change title to "fetching..."

                var interFrame = jQuery('<iframe src="http://www.kink.fm/topic/play_window.php?audioId=' + (this.id.substring(3))
                                        + '" width="25" height="25" style="position: absolute; width:25px; height: 25px; left: 1000px" name="iTransmogrify_' 
                                        + currentItem + '" id="iTransmogrify_' + currentItem + '" />'
                                       )
                interFrame.load( function() {
                    if ( kinkSource = parentObject.mp3regex.exec( jQuery('#iTransmogrify_' + currentItem).contents().find('embed').attr('src') ) )
                         kinkSource = kinkSource[1];
            
                    if ( kinkTitle = (/ - (.*)$/).exec( jQuery('#iTransmogrify_' + currentItem).contents().find('title').text() ) )
                         kinkTitle = kinkTitle[1];
 
                     jQuery('#iTransmogrify_' + currentItem).remove();
                     parentObject.swapTitle(jQuery('#' + currentItem).find('.YTtitle'), kinkTitle);   // swap out the title
                     jQuery('#' + currentItem).find('.YTlink').attr('href', kinkSource);    // point href of main link to the mp3
                     jQuery('#' + currentItem).unbind('click')      // remove previous click handler
                })

                jQuery(this).before(interFrame)

                return false;
            })
        })
	},

		
	getYTTitles: function(YTid) {
		var gdataURL = "http://gdata.youtube.com/feeds/videos/" + YTid + "?alt=json-in-script";
		// can't use JQuery to insert these scripts because of a bug in Google's GData handling 
		// of single-item YouTube feeds, if there's a callback specified then Google spits back 
		// a bad result more info here: http://code.google.com/p/gdata-issues/issues/detail?id=295
		
        // gdata is a placeholder to workaround a Google feed bug with jQuery JSON requests: 
        //      http://code.google.com/p/gdata-issues/issues/detail?id=295
        //      http://code.google.com/p/gdata-issues/issues/detail?id=390
		gdata = { io: { handleScriptLoaded: function(data){ parentObject.YTJSONhandler(data) } } }  
		
        var s = document.createElement('script');
        s.src = gdataURL;
        s.id='script' + YTid;    // for cleanup later on, also used to prevent double-inserted titles
        document.getElementsByTagName('head')[0].appendChild(s); // Gdata will callback to insertYTTitles() after loading the script
		
		// build a fake error handler
		// this will call the insertYTTitles after 2 seconds. The timer clears 
		// in the JSON handler so it will only call on bad script loads
		this['timer' + YTid ] =  setTimeout(function(){ parentObject.insertYTTitles(YTid) }, 4000);	// this is our fake error handler
	},
	
	
	YTJSONhandler: function(data) {
	    // Google recently changed the format of the JSON object's link container. 
	    // this should now recognizes the old version and the new one.
	    // checks for length, which should be a two-item array
	    
	    switch (2) {  
        case ( ( YTid = this.YTregex.exec( data.entry.link[0].href ) ).length ):
            YTid = YTid[1]
            break;

        case ( ( YTid = this.YTregex.exec( data.entry.link[1].href ) ).length ):
            YTid = YTid[1]
            break;

        default:
            YTid = false;
	    }
	    
		if ( YTid ) {
			 this[ YTid ] = data.entry;	// store YT JSON info under the unique ID of the movie
			 clearTimeout( this[ 'timer' + YTid ] )	// clear the timeout (the fake an error handler)
		     this.insertYTTitles( YTid );
		}
	},
	
	insertYTTitles: function(YTid) {
		if ( !this[YTid] ) {
			// movie info failed to load, no JSON data loaded
			var YTtitle = 'Video not found', 
			    YTtime = '--:--';
		} else {
			if ( this[YTid] && jQuery('#script' + YTid).length ) {
				// JSON data loaded and script still exists
				var YTtitle = this[YTid].title.$t,
                    YTtime = this.formatSeconds( this[YTid].media$group.yt$duration.seconds );
			}
		}

        YTtitle = YTtitle + ' &nbsp; <span style="color:#888; font-family:Helvetica;">' + YTtime + '</span>';   // get this out of here
		jQuery('#script' + YTid).remove(); // remove this specific JSON script

        this.swapTitle( jQuery('#' + this.nameCleaner(YTid) + ' .YTtitle'), YTtitle )
	},
	
	swapTitle: function(jq, title) {
	    if ( title.length < 1 ) return false;
	    setTimeout( function() {
	        jq.animate( { textIndent: "-" + jQuery(this).width() +"px" }, 300, function() { jQuery(this).html(title) } ).animate({textIndent: 0}, 500)
		}, 250);
	},
    
	nameCleaner: function(oldName) {
	    // scrubs a string to make it usable as an id/class name
	    return 'iT_' + unescape(oldName).replace(/\W/g, "_");
	},
	
	
	getMP3titles: function(mp3url) {
        this.swapTitle(
            jQuery('#' + this.nameCleaner(mp3url.split('/').pop()) +' .YTtitle'), 
            unescape(mp3url.split('/').pop())
        )
	},
	
	
	getMP3url: function(mp3object) {
		var mp3url,
		    urlCleaner = function(u) {
                if ( u.indexOf('http://') == -1 ) {
                    return window.location.protocol + '//' + window.location.hostname + u
                } else {
                    return u;
                }
            };	
        
		if ( mp3url = this.mp3regex.exec( unescape(mp3object.value) ) ) return urlCleaner( mp3url[1] );
		if ( mp3url = this.mp3regex.exec( jQuery(mp3object).attr('flashvars') ) ) return urlCleaner( mp3url[1] );   // for UFO inserted bare embeds
		return false;
	},
	
	
	getYTid: function(YTobject) {
		var YTid;
		if ( YTid = this.YTregex.exec( YTobject.src ) ) return YTid[1];
		if ( YTid = this.YTregex.exec( YTobject.data ) ) return YTid[1];
		if ( YTid = this.YTinternalRegex.exec( jQuery(YTobject ).attr('flashvars') ) ) return YTid[1];
		if ( YTid = this.YTinternalRegex.exec( YTobject.value ) ) return YTid[1];
		return false;
	},
	
	getDMid: function(DMobject) {
	    
	    
        // THIS IS BEING CALLED TWICE, SECOND CALL THROWS AN ERROR BECUASE THE FIRST CALL REMOVED THE OBJECT
	    
	   var DMid = this.DMregex.exec( DMobject.src );
           
	   if ( DMid[1].length < 17 ){
	       return DMid[1]
       } else {
           var DMidTranslatorUrl = 'http://joemaller.com/services/dailymotion_id_translator.php?DMid=' + DMid[1] + '&_callback=?';
    	   
           jQuery.getJSON( DMidTranslatorUrl + '', function( json ){
                DMid = json.DMid; 
                // console.log('got ID ' + json.DMid);
                // console.log(DMobject);

              parentObject.replaceLinks( {
                  type: "dailymotion",
                  jq: jQuery(DMobject).parent(),
                  DMid: json.DMid
              } );
              parentObject.getDMtitles(json.DMid);

          } );
              // console.log('fetching id from remote service for ' + DMid[1]);
       }
	},
	

	getQTtags: function(iT){
        // checks for existance of the QT library first, then inserts the tags once loaded

        if (typeof(iT._bg) == "undefined") iT._bg = "transparent";

        var QTtag = function() {
            var QT = '<div style="cursor:pointer;">\n'
                    + QT_GenerateOBJECTText_XHTML( iT._img, iT._w, iT._h - iT.bar.h , "",
                                                  "href", iT._mp4,
                                                  "autoplay", "false",
                                                  "controller", "false",
                                                  "target", "myself",
                                                  "scale", "aspect",
                                                  "type", "audio/x-mpeg" )
                    + '</div>';

           jQuery( '#' + parentObject.nameCleaner(iT._id) + ' a.YTlink:first ').replaceWith(QT)
        };


	    if ( typeof(QT_WriteOBJECT_XHTML) != "function" ) { 
	        jQuery.getScript( this.appleQuickTimeLib, QTtag );
        } else {
	        QTtag()
	    }
        return "getQTtags finished";
	},
	
	formatSeconds: function(seconds) { if (seconds <= 0) return ''; return parseInt(seconds / 60) + ':' + ( ( seconds % 60 < 10 ) ? '0' + seconds % 60 : seconds % 60 ) },
	
	getDimensions: function(iT) {
    	// adds _w and _h to the iT passed in based on iT._obj. Uses several methods to determine the size.
    
        // if ( iT._w && iT._h )
        //     return true;
            
        var j,    
            w = (!iT._w) ? Math.max(iT._obj.width(), iT._obj.attr('width')) : iT._w,
            h = (!iT._h) ? Math.max(iT._obj.height(), iT._obj.attr('height')) : iT._h;

        // console.log('START getDimensions:  w: ' + w + ',  h: ' + h);
    
        // no dimensions determined, start climbing the dom tree to get dimensions of parents
        if ( !w || !h ) {
            iT._obj.parents().each( function() {
                // console.log('IN UR LOOP getDimensions:  w: ' + w + ',  h: ' + h);
                
                j = jQuery(this);
                // console.log(this.tagName)
                if ( w > 0 && h > 0 )
                    return false;    // ends the jQuery each loop
                if ( !w )
                // console.log(j.width())
                // console.log(j.attr('width'))
                    w = (j.attr('width')) ? Math.max( j.width(), j.attr('width') ) : j.width();
                if ( !h )
                    h = ( j.attr('height') ) ? Math.max( j.height(), j.attr('height') ) : j.height();
            })
        }
        // console.log('END getDimensions:  w: ' + w + ',  h: ' + h);
    	
        iT._w =  w ;
        iT._h =  h ;
	},
	
	getSizes: function(iT) {    // TODO: rename this, it's for sizing boxes, nothing else
	    // assign sizing values for YouTube rectangles
	    // sets the values into known properties of the passed YT object
	    
	    this.getDimensions( iT )

		iT.img.w = iT._w;
		iT.img.h = iT._h;

        if ( typeof(iT._img) != "undefined" ) {
        // if (iT._type == "youtube" || iT._type == "dailymotion" || iT._type == "ted") {
		    iT.img.h -= iT.bar.h;
		    
    		// 0.84 is the default proportion of the YouTube player when the width is <= 400 (400x300 + 36px for the controller)
    		if (iT._w < 400 || iT._h < 336) {
    			// controller will be less than 36px tall
    			if (iT._h/iT._w < 0.84) { 
    				iT.img.w = Math.round(iT._h/0.84);
    				iT.img.h = Math.round(iT.img.w * 0.75);
    			} else {
    				iT.img.h = Math.round(iT._w * 0.75);
    			}
    			
                iT.bar.h = Math.round(iT.img.w * 0.84 - iT.img.w * 0.75);
			
    		} else { 
    			// width greater than 400, controller will be 36px tall
    			if (iT._h/iT._w < (iT._w * 0.75 + 36)/iT._w) { 
    				iT.img.w = Math.round(iT.img.h/0.75);
    			} else {
                    iT.img.h = Math.round(iT.img.w * 0.75);
    			}	
    		}
    		
    		// these variables simplify output positioning
    		iT.img.left = ((iT._w - iT.img.w)/2); 
            iT.img.top = Math.ceil((iT._h - iT.img.h - iT.bar.h)/2);
            iT.bar.top = iT.img.top + iT.img.h;
            
        } else {
            if (iT._h < 36) iT._h = iT.img.h = 36;
            if (iT._w < iT._h * 3) iT._w = iT.img.w = iT._h * 3;
            
            iT.img.left = 0;
            iT.img.top = 0;
            iT.bar.top = 0;
        }
	},
	
	doStats: function() {

        var gaID = "UA-2501271-3";

	    if (typeof(_gat) == 'object') {  // new-style Google Analytics
	        var iTransTracker = _gat._getTracker(gaID); 
	        iTransTracker._initData(); 
            iTransTracker._setDomainName("none");
	        iTransTracker._trackPageview(document.location.toString());
            // console.log('new-style Google Analytics reset ');
            //             console.log(iTransTracker);
        } else if  (typeof(urchinTracker) == 'function') { // old-style Google Analytics
            _uff = 0;   // urchinTracker reset
            _uacct = gaID;
            urchinTracker(document.location.toString());
            // console.log('old-style Google Analytics reset ');
        } else {
            jQuery.getScript((("https:" == document.location.protocol) ? "https://ssl." : "http://www.") + "google-analytics.com/ga.js", function() {
                var iTransTracker = _gat._getTracker(gaID);
                iTransTracker._initData();
                iTransTracker._setDomainName("none");
                iTransTracker._trackPageview(document.location.toString());
                // var iTrans = iTransTracker._createEventTracker('iTransmogrify'); 
                // iTrans._trackEvent('converted', 'this is a test value, will be location?');
                // console.log('New google Analytics loaded ' + typeof(_gat));
                // console.log(iTransTracker);
            })
        }
	},
	

	
	replaceLinks: function(YT) {			
// console.log(YT)
        if (!YT._type)
            return false


		YT.img = {};
		YT.bar = {};
        // YT._type = YTitem._type;
        // YT._id = YTitem._id;
        // YT._title = YTitem._title
        // YT._bg = (typeof(YTitem._bg) == "undefined") ? '#000' : YT._bg;

		YT.bar.h = 36; // default size for YouTube, scales down if height is less than 36 (YT.img.w * 0.75 + 36)
		
		if (YT._type == "youtube") { 
    		YT._page = 'http://www.youtube.com/watch?v=' + YT._id;
    		YT._img = 'http://img.youtube.com/vi/' + YT._id + '/0.jpg';
    		if ( window.location.host.match( /youtube.com$/ ) ) 
    		    YT._page = 'http://joemaller.com/services/redirector.php?YTid=' + YT._id;       // redirect to escape iPhone-YouTube jail 
    		  
            // YT._w = YTitem._w;
            // YT._h = YTitem._h;
            
            //             if ( typeof(YT._w) == 'undefined' || typeof(YT._h) == 'undefined' ){
            //              YT._w = YT._obj.attr('width');
            //              YT._h = YT._obj.attr('height');
            // }
	    }
	    if (YT._type == "dailymotion") {
	        if (typeof(YT.DMid) == 'undefined') return false;
	        YT._id = YT.DMid;
    		YT._page = 'http://iphone.dailymotion.com/video/' + YT._id;
    		YT._img = 'http://www.dailymotion.com/thumbnail/320x240/video/' + YT._id ;

    		YT._w = YT._obj.attr('width');
		    YT._h = YT._w * 0.75 + 36;
	    }
		if (YT._type == "mp3") {
		    YT._id = YT._mp3.split('/').pop();	
		    YT._page = YT._mp3;	    
		    YT._title = this.getMP3titles(YT._mp3);
            
            // YT._w = YT._obj.parent().width();
            // YT._h = YT._obj.parent().height();
		}
		

		if ( YT._type == "ted" || YT._type == 'revver' || YT._type == 'blip.tv' || YT._type == 'mp4') {
            // YT._obj = YTitem._obj;
            // YT._mp4 = YTitem._mp4;
            // YT._img = YTitem._img;
            // YT._bg = YTitem._bg;
            // YT._id = YTitem._id;
            // YT.img.url = YTitem._img;
            // YT._title = YTitem._title;
            // YT._w = YTitem._w;
            // YT._h = YTitem._h;
            // YT.url = YTitem._page;
            // YT._duration = YTitem._duration;
    		YT._title = YT._title += ' &nbsp; <span style="color:#888; font-family:Helvetica;">' + YT._duration + '</span>'
		}
        
        this.getSizes(YT);

		YT.div = '<div class="YTblock" id="' + this.nameCleaner(YT._id) + '" style="\
    									 	    width: ' + YT._w +'px; \
    										    height: ' + YT._h + 'px; \
    										    display: inline-block;	\
    										    position: relative; \
    										    margin: 0;	\
                                                background: ' + YT._bg + '; \
    										    padding: 0 0 0 0; \
    										    text-align: center; \
    										    line-height: 0;">';
								
		YT.link = '<a class="YTlink" href="' + YT._page + '" target="_new" style="\
                                                background: green; \
                                                text-decoration: none;">';
		
		YT.button = '<div class="YTbutton" style="\
												position: absolute; \
												width: ' + YT._w + 'px; \
												height: ' + YT.img.h + 'px; \
												left: 0; \
												top: 0; \
												margin: 0; \
												padding: 0; \
												background: transparent url(' + this.imageBaseURL + 'play.png) no-repeat center center; " />';
												
		YT.img.tag = '<img src="' + YT._img + '" style="\
												position: absolute; \
												top: ' + YT.img.top + 'px; \
												left: ' + YT.img.left + 'px; \
												width: ' + YT.img.w + 'px; \
												height: ' + YT.img.h + 'px; \
												border:none; \
												margin: 0; \
												padding: 0;" />';
																					
		YT.bottom = '<img class="YT.bottom" src="' + this.imageBaseURL + 'bar.png" style="\
												position: absolute; \
												top: ' + YT.bar.top + 'px; \
												left: 0; \
												height: ' + YT.bar.h + 'px; \
												width:' + YT._w + 'px; \
												border: none; \
												padding: 0; \
												margin: 0; \
												background: transparent;"/>';
												
		YT.titlediv = '<div class="YTtitle" style="\
												position: absolute; \
												left: 0; \
												top: ' + YT.bar.top + 'px; \
												width: ' + (YT._w - YT.bar.h/2) + 'px; \
												padding: ' + Math.floor(YT.bar.h/4) + 'px; \
												margin: 0; \
												font: ' + (YT.bar.h * 0.5) + 'px helvetica; \
                                                -webkit-text-size-adjust: none; \
												text-align: left;  \
												line-height: ' + (YT.bar.h * 0.5) + 'px; \
												color: #ddd; \
												white-space: nowrap; \
												overflow: hidden;';
												
		if (YT._type == 'mp3') YT.titlediv += 'background: transparent url(' + this.imageBaseURL + 'music.png) no-repeat left center;\
		                                        width: ' + (YT.img.w - YT.bar.h/2 - 32) + 'px; \
		                                        padding-left: 32px;'									
		YT.titlediv += '">';

        if (YT._title) { 
            YT.titlediv += YT._title; 
        } else {
            if ( YT._type == 'youtube' )       YT.titlediv += 'Open in YouTube Viewer';
            if ( YT._type == 'dailymotion' )   YT.titlediv += 'View on DailyMotion';
            if ( YT._type == 'mp3' )           YT.titlediv += 'Listen to MP3';
        }
        
        YT.titlediv += '</div>';
												
		YT.infoLink = '<img src="' + this.imageBaseURL + 'fade.png" style="\
				                                position: absolute; \
												top: ' + YT.bar.top + 'px; \
												left: ' + (YT._w - YT.bar.h * 2) + 'px; \
												height: ' + YT.bar.h + 'px; \
												width: ' + (YT.bar.h * 2) + 'px; \
												border: none; \
												padding: 0; \
												margin: 0; \
												background: transparent;" />\
		              <a class="YT.infoLink" href="' + this.joesInfoURL + '" target="_blank" style="\
												position: absolute; \
												top: ' + YT.bar.top + 'px; \
												text-decoration: none; \
												left: ' + (YT._w - YT.bar.h) + 'px; \
												background: transparent; \
												border: none; \
    											padding: 0; \
												margin: 0; \
	                                            text-decoration: none;"> \
				      <img src="' + this.imageBaseURL + 'info.png" style="\
												width:' + YT.bar.h + 'px; \
												border: none; \
												background: transparent; \
												max-width: none; \
												margin:0; \
												padding:0;" /></a>';


        YT.sponsor = '<div style="width: ' + (YT._w) + 'px; background:pink;"><div style="\
                                                background: #888; \
                                                color: #bbb; \
                                                -moz-border-radius: ' + (YT._w * 0.92 / 32) + 'px; \
                                                -webkit-border-radius: ' + (YT._w * 0.92 / 32 ) + 'px; \
                                                -webkit-text-size-adjust: none; \
                                                -webkit-border-image: url(' + this.imageBaseURL + 'sponsor.png)  17 / 10px stretch stretch; \
												font: ' + (YT.bar.h * 0.33) + 'px helvetica; \
                                                line-height: ' + (YT.bar.h * 0.1) + 'px; \
                                                width: 90%; \
												white-space: nowrap; \
                                                overflow: show; \
                                                text-align: center; \
                                                margin: 2px 4%; \
                     ">I AM TOO LONG TO FIT, YOU CAN DELETE ME iTransmogrify sponsorship opportunities available <a style="color:white;" href="mailto:joe@joemaller.com?subject=iTransmogrify+sponsorship">email me</a></div>'; // this obviously needs to pull in from somethign remote, also fix unsupported and Flickr badges
                                                
        if ( typeof(YT._mp4) != "undefined" )
            YT.button = YT.img.tag = ''; // clear playbutton and base image (flashes) under MP4s

        if ( YT._type == 'youtube' ) 
            YT.newHTML = (YT.div + YT.link + YT.img.tag + YT.button + YT.bottom + YT.titlediv + "</a>" + YT.infoLink + "</div>");
        if ( YT._type == 'dailymotion' ) 
            YT.newHTML = (YT.div + YT.link + YT.img.tag + YT.button + YT.bottom + YT.titlediv + "</a>" + YT.infoLink + "</div>");
        if ( YT._type == 'mp3' )    		
            YT.newHTML = (YT.div + YT.link + YT.bottom + YT.titlediv + "</a>" + YT.infoLink + "</div>");
        if ( YT._type == 'ted' || YT._type == 'revver' || YT._type == 'blip.tv' || YT._type == 'mp4')
            YT.newHTML = (YT.div + YT.link + YT.img.tag + YT.button + "</a>" + YT.link + YT.bottom + YT.titlediv + "</a>" + YT.infoLink + "</div>");
        
        // YT.newHTML += YT.sponsor;
        
        YT._obj.replaceWith(YT.newHTML);
        
        if ( typeof(YT._mp4) != "undefined" && YT._mp4 != '' )
          this.getQTtags(YT);
          
		if ( YT._type == 'youtube' )
		    this.getYTTitles(YT._id); // replace YouTube titles
	},

	replaceUnsupported: function(jQ) {			
        var w, h, knownText, notYetText, unsupportedText;
        doesNotYet = " does not yet offer iPod/iPhone compatible videos";

        if ( !jQ.jquery ) {
            this.unsupported.replace(jQ);
        } else {
            
    	    // MotionBox
            if ( knownText = ( /motionbox.com.*id%3D([^%]+)%/ ).exec( jQ.attr('src') ) ) 
                unsupportedText = '<a href="http://www.motionbox.com/video/player/' + knownText[1] + '" target="_new">MotionBox video page</a><br /> Motion Box' + doesNotYet;
        
    	    // RedLasso
            var redLassoRegex = /redlasso.com/;
        
            if ( ( knownText = redLassoRegex.exec( jQ.attr('src')) ) ||
                 ( knownText = redLassoRegex.exec( jQ.children('param').attr('value') ) ) 
               ) 
                unsupportedText = '<a href=""></a>RedLasso' + doesNotYet + "<br /> iTransmogrify! <a href='mailto:joe+joemaller+com?subject=RedLasso%20invite%20for%20iTransmogrify%21'>needs an invite</a>, spare one?".replace(/(mailto:[^+]+)\+([^+]+)(?:\+|\.)?([^+?]+)?/,'$1@$2.$3');

            // viddler
            var viddlerRegex = /viddler.com\/(?:player|simple)\/([a-zA-Z0-9]+)/;
            if ( ( knownText = viddlerRegex.exec( jQ.attr('src') ) ) ) 
                this.unsupported.replace({_obj: jQ.parent('object'), _typeLabel:'Viddler'});


            // vimeo
            var vimeoRegex =  /vimeo.com\/.*clip_id=([0-9]+)&/
             if ( knownText = vimeoRegex.exec( jQ.attr('data') ) ) 
                unsupportedText = '<a href="http://www.vimeo.com/' + knownText[1] + '" target="_new">Vimeo video page</a><br /> Vimeo' + doesNotYet;


             // liveleak thumbnail location can be retrieved via page headers, looks like this:  http://cdn-##.liveleak.com/liveleak/thumbs/####/Month/#/444b68e2178658_1_thumb-big.jpg
             if ( ( knownText = ( /liveleak.com\/.*token=([_0-9]+)/).exec( jQ.attr('data') ) ) ||
                  ( knownText = ( /&token=([_0-9]+)/).exec( jQ.attr('flashvars') ) ) ) 
                unsupportedText = '<a href="http://www.liveleak.com/view?i=' + knownText[1] + '" target="_new">LiveLeak video page</a><br /> LiveLeak' + doesNotYet;
          
          
            // NBC
            var nbcRegex = /widgets.nbc.com/;
            if ( knownText = nbcRegex.exec( jQ.attr('src') ) ) 
               unsupportedText = '<a href="http://www.nbc.com/" target="_new">NBC video page</a><br /> NBC' + doesNotYet;
        
        
            // MegaVideo
            var megaVideoRegex = /megavideo.com\/v\/([A-Z0-9]+)[a-z0-9]{32}\.[0-9]{10}\.[0-9]$/;
        
            if ( ( knownText = megaVideoRegex.exec( jQ.attr('src')) ) ||
                 ( knownText = megaVideoRegex.exec( jQ.children('param[value*=megavideo]').attr('value') ) ) 
               ) 
               this.unsupported.replace({_obj: jQ, _page:'http://www.megavideo.com/?v=' + knownText[1], _typeLabel:'MegaVideo', _title:"Video Page"});
    
            // insert unsupported placeholder message 
            if ( unsupportedText ) {
                var unsupported = jQuery(''
                    + '<div "style="\
                                   width:' + w + 'px; \
                                   height:' + h + 'px; \
                                   position: relative; \
                                   font-family: Helvetica; \
                                   color: #888; \
                                   margin: 0; \
                                   padding: 0; \
                                   font-size: ' + ( ( h/10 < 28 ) ? h/10 : 28 ) + 'px; \
                                   display:block; ">'
                    + '<div style="position: absolute; \
                                   margin: 0; \
                                   padding: 0; \
                                   width:100%; \
                                   height: 100%; \
                                 ">\
                      <img src="'+ this.imageBaseURL + 'unsupported.png" style="\
                                  width:100%; \
                                  height: 100%;">\
                      </div>'
                    + '<div style="\
                                   position: absolute;\
                                   display: table; \
                                   opacity: 0.75; \
                                   height: 100%;\
                                   width: 100%; \
                                   text-shadow: #000 0 0.2em 0.25em; \
                                   ">\
                        <div style="display:table-cell; \
                                   padding: 0 10%; \
                                   vertical-align: middle; \
                                   text-align: center; \
                                   font-size: 0.8em; \
                                   line-height: 1.6em; \
                                    ">'
                    + unsupportedText
                    + '\
                     <a href="http://itransmogrify.googlecode.com" target="_new" style="\
                                  position: absolute; \
                                  margin: 0; \
                                  padding: 0; \
                                  right: 10px; \
                                  bottom: 0; \
                                  font-size: 0.8em; \
                                  ">\
                         iTransmogrify!\
                       </a>'
                    + '</div>'
                    + '</div>'
                    + '</div>'
    	        );

                unsupported.find('a').css( { color: '#fff', textDecoration: 'none', fontWeight: 'bold', opacity: 0.5 } ).eq(0).css( { fontSize: '1.25em', opacity: 0.75 } )
                // jQ = (jQ.parent().is('object') ) ? jQ.parent() : jQ;
                jQ.replaceWith(unsupported)
            };
        }
    },
    
    // going to transition unsupported over to this object
    unsupported: {
        doesNotYet: " does not yet offer iPod/iPhone compatible videos",
        
        replace: function(iT) {
            // 
            // console.log('in unsupported.replace()._img:' + iT._img)
            // console.log(iT)
            parentObject.getDimensions(iT);
            // console.log('post getDimensions')
            // console.log(iT)
 
            var output, img, imgDiv, textDiv, outerDiv, tablediv, message;
                                 
            if (!iT._typeLabel)
                iT._typeLabel = '';

        
            // outerdiv                      
            outerDiv = jQuery(document.createElement('div')).css({width: iT._w + 'px', 
                                             height: iT._h + 'px', 
                                             position: 'relative', 
                                             fontFamily: 'helvetica', 
                                             color: '#aaa',
                                             background: '#555',
                                             margin: 0,
                                             padding: 0,
                                             fontSize: iT._h/14 + "px", // base line-height on 14 theoretical lines in the box. Seems ok
                                             display: 'block'
                                            })
                                       
                                          
          textDiv = jQuery(document.createElement('div')).css({ display: 'table-cell', 
                                           position: 'relative',
                                           width: '100%', 
                                           height: '100%', 
                                           padding: '0 10%', 
                                           verticalAlign: 'middle', 
                                           textAlign: 'center', 
                                           fontSize: '0.8em', 
                                           lineHeight: '1.6em'}
                                          ) 

          if ( iT._title ) {
              if (iT._page && iT._page != document.location.href) {              
                  textDiv.append(jQuery(document.createElement('a')).attr({'href': iT._page, 'target': '_new'}).text(iT._title).css( { color: '#fff', textDecoration: 'none', fontWeight: 'bold', fontSize: '1.25em', opacity: 0.75 } ))
              } else {
                  textDiv.append(jQuery(document.createElement('span')).text(iT._title).css( { fontWeight: 'bold', fontSize: '1.25em' } ))
              }
              textDiv.append(document.createElement('br'));
          }
          textDiv.append('This ' + iT._typeLabel  + ' video is not yet available in a MobileSafari compatible format.'); // TODO sniff whether or not this is an iPhone or iPod Touch, use that instead of 'MobileSafari'
        
          
          textDiv = jQuery(document.createElement('div')).css({ position: 'absolute', 
                                           display: 'table', 
                                           height: '100%', 
                                           width: '100%', 
                                           textShadow: '#000 0 0.2em 0.25em'
                                        }).append(textDiv)
          
          // background image overlay:
          imgDiv = jQuery(document.createElement('div')).append( 
                      jQuery(document.createElement('img')).attr('src', parentObject.imageBaseURL + 'unsupported.png').css({width: '100%', height: '100%', padding: 0, margin: 0, background: 'transparent'}) 
                   ).css({ position: 'absolute', 
                           top: 0, 
                           left: 0, 
                           margin: 0, 
                           padding: 0, 
                           width: '100%', 
                           height: '100%'
                      });

          if (iT._img) {    
              var bgImgDiv = imgDiv.clone();
              bgImgDiv.children('img').attr('src', iT._img);
              bgImgDiv.css('opacity', '0.6')
              outerDiv.prepend(bgImgDiv);
          }
            outerDiv.append(imgDiv).append(textDiv)
          outerDiv.append(
              jQuery(document.createElement('a')).attr({'href':'http://itransmogrify.googlecode.com', 'target':'_new'}).css({
                  position: 'absolute',
                  margin: 0, padding: 0, bottom: '0.5em', right: '10px', fontSize: '0.7em', fontWeight: 'bold', color: '#888', textDecoration: 'none'
              }).text('iTransmogrify!')
          )

            iT._obj.replaceWith(outerDiv)
            console.log('end')
        }
    }
}.init()


// Known issues
// TODO: Fix LiveLeak unsupported embeds
// TODO: Fix MP3 sizing
// TODO: DailyMotion is broken